# Port of hal.tcl (Eggdrop "learn" script)
# Orginially by Hal9000 @ irc.ptnet.org

#import re
import string
#import threading
import time
import fileinput

irc = None
hal_doc = "learn.dat"
channels = ["#liek"]
flood_list = {}

def init(bot):
    global irc

    bot.cmd.events['PRIVMSG'].subscribe(privmsg);
    irc = bot

def privmsg(sender, args):
    global irc, hal_doc, channels, flood_list

    if irc.irclower(args[2]) not in channels:
        # ignore -> we don't work here
        return

    argv = args[0].split(' ')
    
    if len(argv) == 0:
        return

    if len(argv[0]) == 0 or argv[0].isspace():
        return

    if argv[0] == '??':
        if len(argv) < 2:
            irc.notice(sender.nick, "Try ?? word || ?? word > target")
            return
        
        term = argv[1].lower()
        target = irc.irclower(args[2])

        if len(argv) >= 4:
            if argv[2] == '>' or argv[2] == '>>':
                target = irc.irclower(argv[3])

        if flood_list.has_key((term, target)):
            if int(time.time()) - flood_list[(term, target)] > 60:
                del flood_list[(term, target)]
            else:
                irc.privmsg(args[2], "\002Hey %s, I've already told you about \"%s\"... no need to repeat (I think)\002" % (sender.nick, term))
                return
        
        flood_list[(term, target)] = int(time.time())

        try:
            fh = open(hal_doc)
        except IOError:
            irc.privmsg(args[2], 'Error opening definition file!')
            return

        matched_lines = []

        for line in fh:
            l = line.rstrip()

            split_line = l.split(None, 2)

            if len(split_line) < 3:
                continue
            
            if split_line[1] == term:
                matched_lines.append(split_line[:])
        fh.close()

        # XXX: Here we should be checking who we're sending to

        if len(matched_lines) < 1:
            irc.privmsg(target, get_output(term, 'x', 'No definition found for word.'))
        elif len(matched_lines) == 1:
            irc.privmsg(target, get_output(term, None, matched_lines[0][2]))
        else:
            count = 0
            for i in matched_lines:
                count += 1
                irc.privmsg(target, get_output(term, count, i[2]))
        
        # XXX: Would be nice to have a good way of clearing this list... mabye some other time
        #t = threading.Timer(60, clear_flood, [term, target])
        #t.start()

    elif argv[0] == '**':
        if len(argv) < 2:
            # Show usage
            pass

        _, search = args[0].split(' ', 1)
        search = search.lower()

        start_clock = time.clock()

        try:
            fh = open(hal_doc)
        except IOError:
            irc.privmsg(args[2], 'Error opening definition file!')
            return
        
        matched_terms = []

        for line in fh:
            l = line.rstrip()

            split_line = l.split(None, 1)

            if len(split_line) < 2:
                continue
            
            term = split_line[1].split(None, 1)[0]
            term = term.lower()
            split_line[1] = split_line[1].lower()

            if term in matched_terms:
                continue
            
            if search in split_line[1]:
                if len(matched_terms) >= 10:
                    time_elapsed = time.clock() - start_clock
                    irc.privmsg(args[2], "\002Too many matches.\002 Try a more complex search. (\002\037%s\037s\002)" % round(time_elapsed, 3))
                    fh.close()
                    return

                matched_terms.append(term)
        fh.close()

        if len(matched_terms) > 0:
            matched_terms.sort()
            
            idx = 0
            while idx < len(matched_terms):
                matched_terms[idx] = ("\037%s\037" % matched_terms[idx])
                idx = idx + 1
            
            time_elapsed = time.clock() - start_clock

            irc.privmsg(args[2], ("\002Found \037%d\037 matches.\002 Sorted: %s. (\002\037%s\037s\002)" % (len(matched_terms), string.join(matched_terms, ', '), round(time_elapsed, 3))))
        else:
            time_elapsed = time.clock() - start_clock
            irc.privmsg(args[2], ("Sorry, no matches for %s in the definition database. (\002\037%s\037s\002)" % (search, round(time_elapsed, 3))))

    elif argv[0] == "!learn":
        # XXX: Needs an auth system, but for now we'll go for chanops
        if not irc.chmgr.get(args[2]).isop(sender.nick):
            return

        # !learn command term [idx] [def]

        if len(argv) < 3:
            irc.notice(sender.nick, "Syntax: !learn (add, rem, ins, rep) [index] [definition]")
            return
        
        if argv[1] == 'add':
            if len(argv) < 4:
                irc.notice(sender.nick, "Try !learn add word definition")
                return

            _, _, term, definition = args[0].split(None, 3)
            term = term.lower()
            inserted = False
            try:
                for line in fileinput.input(hal_doc, inplace=1):
                    if not inserted:
                        _, line_term, _ = line.split(None, 2)
                        line_term = line_term.lower()
                        if line_term > term:
                            print "%s %s %s" % (sender.nick, term, definition)
                            inserted = True
                    print line,
            except IOError:
                irc.notice(sender.nick, "Unable to open dictionary file.")

            if not inserted:
                try:
                    fh = open(hal_doc, 'a')
                    print >>fh ("%s %s %s" % (sender.nick, term, definition))
                    fh.close()
                except IOError:
                    irc.notice(sender.nick, "Error writing to dictionary file.")
                    return

            irc.notice(sender.nick, "Definition added.")


        elif argv[1] == 'rem':
            if len(argv) == 3:
                remove = 0
            else:
                if not argv[3].isdigit():
                    remove = 0
                remove = int(argv[3])

            term = argv[2].lower()

            count = 0
            removed = False
            found_any = False
            try:
                for line in fileinput.input(hal_doc, inplace=1):
                    if not removed:
                        _, line_term, _ = line.split(None, 2)
                        line_term = line_term.lower()
                        if line_term == term:
                            count = count + 1
                            if count == remove:
                                removed = True
                                continue
                            elif remove == 0:
                                # Remove all
                                found_any = True
                                continue
                    print line,
            except IOError:
                irc.notice(sender.nick, "Error writing to dictionary file.")
                return
            
            if removed or found_any:
                irc.notice(sender.nick, "Definition removed.")
            else:
                irc.notice(sender.nick, "Couldn't find that word in my dictionary.")

        elif argv[1] == 'ins':
            if len(argv) < 5:
                irc.notice(sender.nick, "Try !learn ins word loc definition")
                return
            else:
                if not argv[3].isdigit():
                    irc.notice(sender.nick, "Location must be an integer")
                    return
                location = int(argv[3])
            
            _, _, term, _, definition = args[0].split(None, 4)
            term = term.lower()
            count = 0
            inserted = False

            # XXX: We assume the file is sorted properly. If it isn't: your fault when things go wrong :)
            try:
                for line in fileinput.input(hal_doc, inplace=1):
                    if not inserted:
                        _, line_term, _ = line.split(None, 2)
                        line_term = line_term.lower()
                        if line_term == term:
                            count = count + 1
                            if count >= location:
                                print "%s %s %s" % (sender.nick, term, definition)
                                inserted = True
                        elif line_term > term:
                            print "%s %s %s" % (sender.nick, term, definition)
                            inserted = True
                    print line,
            except IOError:
                irc.notice(sender.nick, "Error opening dictionary file.")
            
            if not inserted:
                # Ouch, EOF
                try:
                    fh = open(hal_doc, 'a')
                    print >>fh ("%s %s %s" % (sender.nick, term, definition))
                    fh.close()
                except IOError:
                    irc.notice(sender.nick, "Error writing to dictionary file.")
                    return
            
            irc.notice(sender.nick, "Definition inserted")

        elif argv[1] == 'rep':
            # !learn rep word idx def
            if len(argv) < 5:
                irc.notice(sender.nick, "Try !learn rep word loc definiion")
                return
            else:
                if not argv[3].isdigit():
                    irc.notice(sender.nick, "Location must be an integer")
                    return
                location = int(argv[3])
                if location < 1:
                    irc.notice(sender.nick, "Location starts at 1")
                    return

            _, _, term, _, definition = args[0].split(None, 4)
            term = term.lower()
            replaced = False
            count = 0

            try:
                for line in fileinput.input(hal_doc, inplace=1):
                    if not replaced:
                        _, line_term, _ = line.split(None, 2)
                        line_term = line_term.lower()
                        if line_term == term:
                            count = count + 1
                            if count == location:
                                print "%s %s %s" % (sender.nick, term, definition)
                                replaced = True
                            else:
                                print line,
                        else:
                            print line,
                    else:
                        print line,
            except IOError:
                irc.notice(sender.nick, "Error opening dictionary file.")
                return
            
            if replaced:
                irc.notice(sender.nick, 'Definition replaced.')
            else:
                irc.notice(sender.nick, "I couldn't find that definition in my dictionary.")
            

def get_output(word, index, definition):
    if index:
        return "\002\037%s[\037\002%s\002\037]\037\002: %s" % (word, index, definition)
    else:
        return "\002\037%s\037\002: %s" % (word, definition)

def clear_flood(term, target):
    global flood_list

    flood_list.remove((term, target))
